#include "paramadd.h"
#include "ui_paramadd.h"
#include <QMessageBox>
#include <QRegExp>
#include <QValidator>
#include "shadow.h"
#include "msgbox.h"
#include "frminput2019.h"
#include "userlogger.h"

ParamAdd::ParamAdd(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::ParamAdd)
{
    ui->setupUi(this);
    bdf = BllDataFlow::getInstance();
    sqlHelper = SqlHelper::getInstance();

    //Signals and Slots
    connect(bdf, &BllDataFlow::retranslateUiSignal, this, &ParamAdd::retranslateUiSlot);

    initWidget();
}

ParamAdd::~ParamAdd()
{
    delete ui;
}

void ParamAdd::paintEvent(QPaintEvent *)
{
    QPainter painter(this);
    painter.fillRect(this->rect(), QColor(255, 255, 255, 0));
}

void ParamAdd::showEvent(QShowEvent *)
{
    this->activateWindow();
}

void ParamAdd::on_btnClose_clicked()
{
    this->hide();
}

void ParamAdd::on_btnCancel_clicked()
{
    this->hide();
}

static void focusOn(QLineEdit *lineEdit)
{
    if (lineEdit)
    {
        lineEdit->selectAll();
        lineEdit->setFocus();
    }
}

void ParamAdd::autoFocusOn()
{
    // 焦点转换表
    const QMap<QLineEdit *, QLineEdit *> mapper = {
        {ui->lineName, ui->lineCode},
        {ui->lineCode, ui->spinVolt->findChild<QLineEdit *>()},
        {ui->spinVolt->findChild<QLineEdit *>(), ui->spinPulse->findChild<QLineEdit *>()},
        {ui->spinPulse->findChild<QLineEdit *>(), ui->spinSpeed->findChild<QLineEdit *>()},
        {ui->spinSpeed->findChild<QLineEdit *>(), ui->spinInterval->findChild<QLineEdit *>()},
        {ui->spinInterval->findChild<QLineEdit *>(), ui->spinTimes->findChild<QLineEdit *>()},
        {ui->spinTimes->findChild<QLineEdit *>(), Q_NULLPTR}
    };

    QLineEdit *lineEdit = qobject_cast<QLineEdit *>(QObject::sender());
    if (lineEdit)
    {
        lineEdit->deselect();
        Q_ASSERT(mapper.contains(lineEdit));
        focusOn(mapper[lineEdit]);
    }
}

void ParamAdd::on_btnConfirm_clicked()
{
    frmInput2019::Instance()->hideAndClearFocus();

    param.name = ui->lineName->text().trimmed();
    param.code = ui->lineCode->text().trimmed();
    param.volt = ui->spinVolt->value();
    param.pulse = ui->spinPulse->value();
    param.interval = ui->spinInterval->value();
    param.speed = ui->spinSpeed->value();
    param.times = ui->spinTimes->value();
    param.ison = ui->btnIsOn->isChecked();

    if (param.name.isEmpty())
    {
        MsgBox::information(this, QString(tr("Parameter")), QString(tr("Parameter name cannot be empty!")));
        focusOn(ui->lineName);
        return;
    }

    if (sqlHelper->checkParamNameExist(param.name))
    {
        MsgBox::information(this, QString(tr("Parameter")), QString(tr("Parameter name exists already!")));
        focusOn(ui->lineName);
        return;
    }

    if (param.code.isEmpty())
    {
        MsgBox::information(this, QString(tr("Parameter")), QString(tr("Parameter code cannot be empty!")));
        focusOn(ui->lineCode);
        return;
    }

    if (param.volt < DOUBLE_PRECISION)
    {
        MsgBox::warning(this,QString(tr("Parameter")),QString(tr("Volt shouldn't be zero.")));
        return;
    }

    if (param.speed < DOUBLE_PRECISION)
    {
        MsgBox::warning(this,QString(tr("Parameter")),QString(tr("Speed shouldn't be zero.")));
        return;
    }

    if (param.pulse < DOUBLE_PRECISION)
    {
        MsgBox::warning(this,QString(tr("Parameter")),QString(tr("Pulse shouldn't be zero.")));
        return;
    }

    if (param.interval < DOUBLE_PRECISION)
    {
        MsgBox::warning(this,QString(tr("Parameter")),QString(tr("Interval shouldn't be zero.")));
        return;
    }

    if (param.times < DOUBLE_PRECISION)
    {
        MsgBox::warning(this,QString(tr("Parameter")),QString(tr("Times shouldn't be zero.")));
        return;
    }

    UserLogger::log(QString("%1: %2(%3)\n>%4: %5V, %6: %7μs, %8: %9ml/min, %10: %11ms, %12: %13")
                    .arg(tr("Add parameters")).arg(param.name).arg(param.code)
                    .arg(tr("Voltage")).arg(param.volt)
                    .arg(tr("Pulse")).arg(param.pulse)
                    .arg(tr("Flow Rate")).arg(param.speed)
                    .arg(tr("Interval")).arg(param.interval)
                    .arg(tr("Times")).arg(param.times));

    EttaError ret = sqlHelper->insertParameterItem(param);
    if (EttaError::OK == ret)
    {
        QString message = tr("Success to add parameter");
        UserLogger::log(QString("%1: %2(%3)").arg(message).arg(param.name).arg(param.code));
        bdf->showAllParameters(true);
        this->hide();
    }
    else
    {
        QString message = tr("Fail to add parameter");
        UserLogger::log(QString("%1: %2(%3)").arg(message).arg(param.name).arg(param.code));
        MsgBox::warning(this, tr("Parameter"), message);
    }
}

void ParamAdd::on_btnIsOn_toggled(bool checked)
{
    if (checked)
    {
        QList<QStringList> info = sqlHelper->parameterEnableCount();
        int enableCount = info.size();
        if (enableCount >= MAX_PARAMETER_COUNT && !param.ison)
        {
            param.ison = false;
            ui->btnIsOn->setChecked(false);
            MsgBox::information(this, tr("Parameter"), tr("Enable up to %1 parameters").arg(MAX_PARAMETER_COUNT));
        }
        else
        {
            param.ison = true;
            ui->btnIsOn->setText(QString(tr("On")));
            ui->btnIsOn->setStyleSheet(NormalBtnEnableCss);
        }
    }
    else
    {
        param.ison = false;
        ui->btnIsOn->setText(QString(tr("Off")));
        ui->btnIsOn->setStyleSheet(NormalBtnDisEnableCss);
    }
}

void ParamAdd::initWidget()
{
    setAttribute(Qt::WA_TranslucentBackground, true);
    QGraphicsDropShadowEffect *shadow = new QGraphicsDropShadowEffect();
    shadow->setColor(QColor(0,0,0,150));
    shadow->setOffset(1, 1);
    shadow->setBlurRadius(16);
    ui->widget->setGraphicsEffect(shadow);
    setWindowFlags(windowFlags() | Qt::SubWindow);
    param.volt = 30;
    param.pulse = 10;
    param.interval = 10;
    param.speed = 1;
    param.times = 0;
    param.ison = false;
    ui->btnIsOn->setStyleSheet(NormalBtnDisEnableCss);
    ui->btnIsOn->setText(tr("Off"));

    foreach (const QSpinBox *spinBox, findChildren<QSpinBox *>())
    {
        spinBox->findChild<QLineEdit *>()->setPlaceholderText(QString("%1-%2").arg(spinBox->minimum()).arg(spinBox->maximum()));
    }

    foreach (const QDoubleSpinBox *spinBox, findChildren<QDoubleSpinBox *>())
    {
        spinBox->findChild<QLineEdit *>()->setPlaceholderText(QString("%1-%2").arg(spinBox->minimum()).arg(spinBox->maximum()));
    }

    connectSignals();
}

void ParamAdd::clearInput()
{
    disconnectSignals();

    ui->lineName->clear();
    ui->lineCode->clear();
    ui->spinVolt->clear();
    ui->spinPulse->clear();
    ui->spinSpeed->clear();
    ui->spinInterval->clear();
    ui->spinTimes->clear();

    ui->spinVolt->setValue(200);
    ui->spinPulse->setValue(2000);
    ui->spinSpeed->setValue(4.71);
    ui->spinInterval->setValue(688);
    ui->spinTimes->setValue(3.69);

    if (sqlHelper->parameterEnableCount().count() >= MAX_PARAMETER_COUNT)
    {
        ui->btnIsOn->setChecked(false);
        ui->btnIsOn->setText(tr("Off"));
    }
    else
    {
        ui->btnIsOn->setChecked(true);
        ui->btnIsOn->setText(tr("On"));
    }

    connectSignals();
}

void ParamAdd::connectSignals()
{
    connect(ui->spinInterval, SIGNAL(valueChanged(int)), this, SLOT(onUpdateParamTimes()));
    connect(ui->spinPulse, SIGNAL(valueChanged(int)), this, SLOT(onUpdateParamInterval()));
    connect(ui->spinTimes, SIGNAL(valueChanged(double)), this, SLOT(onUpdateParamInterval()));
    connect(ui->spinSpeed, SIGNAL(valueChanged(double)), this, SLOT(onUpdateParamInterval()));

    connect(ui->spinVolt->findChild<QLineEdit *>(), SIGNAL(returnPressed()), this, SLOT(onSpinBoxReturnPressed()));
    connect(ui->spinPulse->findChild<QLineEdit *>(), SIGNAL(returnPressed()), this, SLOT(onSpinBoxReturnPressed()));
    connect(ui->spinSpeed->findChild<QLineEdit *>(), SIGNAL(returnPressed()), this, SLOT(onSpinBoxReturnPressed()));
    connect(ui->spinInterval->findChild<QLineEdit *>(), SIGNAL(returnPressed()), this, SLOT(onSpinBoxReturnPressed()));
    connect(ui->spinTimes->findChild<QLineEdit *>(), SIGNAL(returnPressed()), this, SLOT(onSpinBoxReturnPressed()));
}

void ParamAdd::disconnectSignals()
{
    disconnect(ui->spinInterval, SIGNAL(valueChanged(int)), this, SLOT(onUpdateParamTimes()));
    disconnect(ui->spinPulse, SIGNAL(valueChanged(int)), this, SLOT(onUpdateParamInterval()));
    disconnect(ui->spinTimes, SIGNAL(valueChanged(double)), this, SLOT(onUpdateParamInterval()));
    disconnect(ui->spinSpeed, SIGNAL(valueChanged(double)), this, SLOT(onUpdateParamInterval()));

    disconnect(ui->spinVolt->findChild<QLineEdit *>(), SIGNAL(returnPressed()), this, SLOT(onSpinBoxReturnPressed()));
    disconnect(ui->spinPulse->findChild<QLineEdit *>(), SIGNAL(returnPressed()), this, SLOT(onSpinBoxReturnPressed()));
    disconnect(ui->spinSpeed->findChild<QLineEdit *>(), SIGNAL(returnPressed()), this, SLOT(onSpinBoxReturnPressed()));
    disconnect(ui->spinInterval->findChild<QLineEdit *>(), SIGNAL(returnPressed()), this, SLOT(onSpinBoxReturnPressed()));
    disconnect(ui->spinTimes->findChild<QLineEdit *>(), SIGNAL(returnPressed()), this, SLOT(onSpinBoxReturnPressed()));
}

void ParamAdd::on_lineName_returnPressed()
{
    param.name = ui->lineName->text().trimmed();
    if (param.name.isEmpty())
    {
        MsgBox::information(this, QString(tr("Parameter")), QString(tr("Parameter name cannot be empty!")));
        focusOn(ui->lineName);
        return;
    }

    if (sqlHelper->checkParamNameExist(param.name))
    {
        MsgBox::information(this, QString(tr("Parameter")), QString(tr("Parameter name exists already!")));
        focusOn(ui->lineName);
        return;
    }

    autoFocusOn();
}

void ParamAdd::on_lineCode_returnPressed()
{
    param.code = ui->lineCode->text().trimmed();
    if (param.code.isEmpty())
    {
        MsgBox::information(this, QString(tr("Parameter")), QString(tr("Parameter code cannot be empty!")));
        focusOn(ui->lineCode);
        return;
    }

    autoFocusOn();
}

void ParamAdd::onSpinBoxReturnPressed()
{
    autoFocusOn();
}

void ParamAdd::onUpdateParamTimes()
{
    disconnectSignals();

    param.pulse = ui->spinPulse->value();
    param.speed = ui->spinSpeed->value();
    param.interval = ui->spinInterval->value();

    if (doubleGreater(param.pulse, 0) && doubleGreater(param.speed, 0) && doubleGreater(param.interval, 0))
    {
        param.times = PARAM_VOLUME  / ((param.pulse + param.interval * 1000) * param.speed / 60000);
        ui->spinTimes->setValue(param.times);
    }

    connectSignals();
}

void ParamAdd::onUpdateParamInterval()
{
    disconnectSignals();

    param.pulse = ui->spinPulse->value();
    param.speed = ui->spinSpeed->value();
    param.times = ui->spinTimes->value();

    if (doubleGreater(param.pulse, 0) && doubleGreater(param.speed, 0) && doubleGreater(param.times, 0))
    {
        param.interval = (PARAM_VOLUME * 60) / (param.speed * param.times) - param.pulse / 1000;
        ui->spinInterval->setValue(param.interval);
    }

    connectSignals();
}

void ParamAdd::retranslateUiSlot()
{
    ui->retranslateUi(this);
}
